package com.carleasoft.mps.adu.business.role.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carleasoft.mps.adu.business.role.bean.entity.AuthorityRoleEntity;
import com.carleasoft.mps.adu.business.role.bean.po.RoleParamsPo;
import com.carleasoft.mps.adu.business.role.bean.vo.AuthorityDataPermsVo;
import com.carleasoft.mps.adu.business.role.bean.vo.AuthorityRoleVo;
import com.carleasoft.mps.adu.business.role.dao.AuthorityDataDao;
import com.carleasoft.mps.adu.business.role.dao.AuthorityRoleDao;
import com.carleasoft.mps.adu.business.role.dao.AuthorityTargetRoleDao;
import com.carleasoft.mps.adu.business.role.service.AuthorityPermDataService;
import com.carleasoft.mps.adu.business.role.service.AuthorityPermMenuService;
import com.carleasoft.mps.adu.business.role.service.GrantPermsService;
import com.carleasoft.mps.core.user.Constants;
import com.carleasoft.mps.core.user.ThreadUserContext;
import com.carleasoft.mps.core.user.UserCacheData;
import com.google.common.base.Joiner;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>Description: role serviceImpl</p>
 *
 * @author ztm
 * @since 2020-05-11
 */
@Service
public class GrantPermsServiceImpl extends ServiceImpl<AuthorityRoleDao, AuthorityRoleEntity> implements GrantPermsService {

    @Autowired
    AuthorityDataDao authorityDataDao;
    @Autowired
    AuthorityTargetRoleDao authorityTargetRoleDao;
    @Autowired
    AuthorityPermMenuService permMenuService;
    @Autowired
    AuthorityPermDataService permDataService;


    /**
     * 登录用户能使用的权限
     * 组织管理员使用权限按照用户去获取，跟赋权时查询分开
     * 当数据权限为本部门或者本组织时，数据库并未存储组织或者部门的编码，所以需要从登录缓存中获取
     * 系统管理员和组织管理员均没有默认角色带来的权限，但组织管理员有默认的组织数据权限
     *
     * @return List
     */
    @Override
    public AuthorityRoleVo getAllPermsByUser(Boolean isInc, Boolean isTree) {
        AuthorityRoleVo authorityRoleVo = new AuthorityRoleVo();
        UserCacheData user = ThreadUserContext.getCurrentCacheUser();
        if (user.getUserCat() == Constants.SUPER_ADMIN) {
            authorityRoleVo.setMenuPermsVo(this.permMenuService.getMenuPermListByRoleCode(null,Constants.MENU_SUPPER, true));
            authorityRoleVo.setDataPermsVo(this.permDataService.getDataPermCodesNeedConvert(null, true, isInc));
            if (isTree) {
                this.permDataService.analyseDataPermAsTree(authorityRoleVo.getDataPermsVo());
            }
        } else {
            List<String> roleList = new ArrayList<>();
            if (user.getUserCat() == Constants.SYSTEM_ADMIN) {
                List<String> typeCodesList = new ArrayList<>();
                //个人
                typeCodesList.add(user.getUserCode());

                roleList = this.authorityTargetRoleDao.selectRolesByTargetCodes(typeCodesList, Arrays.asList(Constants.TARGET_SYSTEM_ADMIN));
            }
            if (user.getUserCat() == Constants.ORGANIZATION_SUPER_ADMIN||user.getUserCat() == Constants.ORGANIZATION_SYSTEM_ADMIN) {
                List<String> orgCodesList = new ArrayList<>();
                List<String> targetList = this.authorityDataDao.selectOrgTypeCodes(null, user.getOrgCodeJoin());
                targetList.forEach(item -> {
                    orgCodesList.addAll(Arrays.asList(StringUtils.split(item, Constants.DELIMITER)));
                        }
                );
                if(orgCodesList.size()>0)roleList.addAll(this.authorityTargetRoleDao.selectRolesByTargetCodes(orgCodesList, Arrays.asList(Constants.TARGET_ORGANIZATION_TYPE)));
                roleList.addAll(this.authorityTargetRoleDao.selectRolesByTargetCodes(Arrays.asList(StringUtils.split(user.getOrgCodeJoin(), Constants.DELIMITER)), Arrays.asList(Constants.TARGET_ORGANIZATION)));
            }
            if (user.getUserCat() == Constants.ORDINARY_USER || user.getUserCat() == Constants.ORGANIZATION_SYSTEM_ADMIN) {

                //部门
                List<String> deptCodesList = new ArrayList<>();
                List<String> deptList = this.authorityDataDao.selectAllDeptCode(null, user.getUserCode());
                deptList.forEach(item -> {
                    deptCodesList.addAll(Arrays.asList(StringUtils.split(item, Constants.DELIMITER)));
                });
                roleList.addAll(this.authorityTargetRoleDao.selectRolesByTargetCodes(deptCodesList, Arrays.asList(Constants.TARGET_DEPT)));
                List<String> deptTypeList = this.authorityDataDao.selectDeptTypeCodes(deptCodesList);
                if(CollUtil.isNotEmpty(deptTypeList))
                    roleList.addAll(this.authorityTargetRoleDao.selectRolesByTargetCodes(deptTypeList,Arrays.asList(Constants.TARGET_DEPT_TYPE)));
                //职务和职务分组
                List<String> posList = this.authorityDataDao.selectAllPosCode(null, user.getUserCode());
                if (CollUtil.isNotEmpty(posList))
                    roleList.addAll(this.authorityTargetRoleDao.selectRolesByTargetCodes(posList, Arrays.asList(Constants.TARGET_POS)));
                List<String> posGroupList = this.authorityDataDao.selectAllPosGroupCodes(null, user.getUserCode());
                List<String> posGroupCodesList = new ArrayList<>();
                posGroupList.forEach(item -> {
                    posGroupCodesList.addAll(Arrays.asList(StringUtils.split(item, Constants.DELIMITER)));
                });
                if(posGroupCodesList.size()>0)roleList.addAll(this.authorityTargetRoleDao.selectRolesByTargetCodes(posGroupCodesList, Arrays.asList(Constants.TARGET_POS_GROUP)));
                //个人
                roleList.addAll(this.authorityTargetRoleDao.selectRolesByTargetCodes(Arrays.asList(user.getUserCode()), Arrays.asList(Constants.TARGET_USER)));
                //用户分类
                if(StrUtil.isNotBlank(user.getUserTypeCode()))roleList.addAll(this.authorityTargetRoleDao.selectRolesByTargetCodes(Arrays.asList(user.getUserTypeCode()),Arrays.asList(Constants.TARGET_USER_TYPE)));
            }
            //获取权限
            authorityRoleVo.setMenuPermsVo(this.permMenuService.getMenuPermListByRoleCode(roleList,Constants.MENU_ALL, true));
            authorityRoleVo.setDataPermsVo(this.permDataService.getDataPermCodesNeedConvert(roleList, true, isInc));
            if (isTree) {
                this.permDataService.analyseDataPermAsTree(authorityRoleVo.getDataPermsVo());
            }
        }
        return authorityRoleVo;

    }

    /**
     * 目标对象能使用的权限合集
     * 查询目标对象能拥有那些权限时详情时使用
     *
     * @return List
     */
    @Override
    public AuthorityRoleVo getAllRolesByTargetCode(RoleParamsPo roleParamsPo) {

        //部门分类权限
        if (roleParamsPo.getTargetType() == Constants.TARGET_DEPT_TYPE) {
            return this.getPermsByTargetCode(Arrays.asList(roleParamsPo.getTargetCode()), Arrays.asList(Constants.TARGET_DEPT_TYPE));
        }
        //用户分类权限
        if (roleParamsPo.getTargetType() == Constants.TARGET_USER_TYPE) {
            return this.getPermsByTargetCode(Arrays.asList(roleParamsPo.getTargetCode()), Arrays.asList(Constants.TARGET_USER_TYPE));
        }
        //管理员权限
        if (roleParamsPo.getTargetType() == Constants.TARGET_SYSTEM_ADMIN) {
            return this.getPermsByTargetCode(Arrays.asList(roleParamsPo.getTargetCode()), Arrays.asList(Constants.TARGET_USER));
        }
        //组织分类权限
        if (roleParamsPo.getTargetType() == Constants.TARGET_ORGANIZATION_TYPE) {
            List<String> typeCodesList = new ArrayList<>();
            List<String> targetList = this.authorityDataDao.selectOrgTypeCodes(roleParamsPo.getTargetCode(), null);
            targetList.forEach(item -> {
                typeCodesList.addAll(Arrays.asList(StringUtils.split(item, Constants.DELIMITER)));
            });
            return this.getPermsByTargetCode(targetList, Arrays.asList(Constants.TARGET_ORGANIZATION_TYPE));
        }
        if (roleParamsPo.getTargetType() == Constants.TARGET_ORGANIZATION) {
            List<Integer> type=new ArrayList<>();
            type.add(Constants.TARGET_ORGANIZATION_TYPE);
            type.add(Constants.TARGET_ORGANIZATION);
            List<String> typeCodesList = new ArrayList<>();
            List<String> targetList = this.authorityDataDao.selectOrgTypeCodes(null, roleParamsPo.getTargetCode());
            targetList.forEach(item -> {
                typeCodesList.addAll(Arrays.asList(StringUtils.split(item, Constants.DELIMITER)));
            });
            typeCodesList.add(roleParamsPo.getTargetCode());
            return this.getPermsByTargetCode(typeCodesList,type);
        }
        //部门权限
        if (roleParamsPo.getTargetType() == Constants.TARGET_DEPT) {
            List<Integer> type=new ArrayList<>();
            type.add(Constants.TARGET_DEPT);
            type.add(Constants.TARGET_DEPT_TYPE);
            List<String> typeCodesList = new ArrayList<>();
            List<String> targetList = this.authorityDataDao.selectAllDeptCode(roleParamsPo.getTargetCode(), null);
            targetList.forEach(item -> {
                List<String> removeList = Arrays.asList(StringUtils.split(item, Constants.DELIMITER));
                    typeCodesList.addAll(removeList);
            });
            typeCodesList.add(roleParamsPo.getTargetCode());
            List<String> deptTypeList = this.authorityDataDao.selectDeptTypeCodes(typeCodesList);
            if(deptTypeList!=null)typeCodesList.addAll(deptTypeList);
            return this.getPermsByTargetCode(typeCodesList, type);
        }
        //职务分组权限
        if (roleParamsPo.getTargetType() == Constants.TARGET_POS_GROUP) {
            List<String> typeCodesList = new ArrayList<>();
            List<String> posGroupList = this.authorityDataDao.selectAllPosGroupCodes(roleParamsPo.getTargetCode(), null);
            posGroupList.forEach(item -> {
                typeCodesList.addAll(Arrays.asList(StringUtils.split(item, Constants.DELIMITER)));
            });
            return this.getPermsByTargetCode(typeCodesList, Arrays.asList(Constants.TARGET_POS_GROUP));
        }
        //职务权限
        if (roleParamsPo.getTargetType() == Constants.TARGET_POS) {
            List<Integer> type=new ArrayList<>();
            type.add(Constants.TARGET_POS_GROUP);
            type.add(Constants.TARGET_POS);
            List<String> typeCodesList = new ArrayList<>();
            List<String> posGroupList = this.authorityDataDao.selectAllPosGroupCodes(roleParamsPo.getTargetCode(), null);
            posGroupList.forEach(item -> {
                typeCodesList.addAll(Arrays.asList(StringUtils.split(item, Constants.DELIMITER)));
            });
            typeCodesList.add(roleParamsPo.getTargetCode());
            return this.getPermsByTargetCode(typeCodesList, type);
        }
        //个人权限
        if (roleParamsPo.getTargetType() == Constants.TARGET_USER) {

            List<Integer> type=new ArrayList<>();
            type.add(Constants.TARGET_DEPT);
            type.add(Constants.TARGET_DEPT_TYPE);
            type.add(Constants.TARGET_POS_GROUP);
            type.add(Constants.TARGET_POS);
            type.add(Constants.TARGET_USER);
            type.add(Constants.TARGET_USER_TYPE);
            List<String> typeCodesList = new ArrayList<>();
            //部门及部门分类
            List<String> deptList = this.authorityDataDao.selectAllDeptCode(null, roleParamsPo.getTargetCode());
            deptList.forEach(item -> {
                typeCodesList.addAll(Arrays.asList(StringUtils.split(item, Constants.DELIMITER)));
            });
            typeCodesList.add(roleParamsPo.getTargetCode());
            List<String> deptTypeList = this.authorityDataDao.selectDeptTypeCodes(typeCodesList);
            if(deptTypeList!=null)typeCodesList.addAll(deptTypeList);
            //职务及职务分组
            List<String> posList = this.authorityDataDao.selectAllPosCode(null, roleParamsPo.getTargetCode());
            if (posList != null)
                typeCodesList.addAll(this.authorityTargetRoleDao.selectRolesByTargetCodes(posList, Arrays.asList(Constants.TARGET_POS)));
            List<String> posGroupList = this.authorityDataDao.selectAllPosGroupCodes(null,roleParamsPo.getTargetCode());

            posGroupList.forEach(item -> {
                typeCodesList.addAll(Arrays.asList(StringUtils.split(item, Constants.DELIMITER)));
            });
            //个人及个人分类
           typeCodesList.addAll(Arrays.asList(roleParamsPo.getTargetCode()));
           List<String> userTypeCode=this.authorityDataDao.selectUserTypeCode(roleParamsPo.getTargetCode());
           if(userTypeCode!=null)typeCodesList.addAll(userTypeCode);

            return this.getPermsByTargetCode(typeCodesList, type);

        }
        return null;
    }


    /**
     * 修改权限时，先查询修改人所拥有的权限，在查询目标对象所拥有的权限，如果目标对象没有被修改过权限，则按照系统默认方式加载权限
     * 和角色查询共同使用一个接口，可以传业务code或者角色code，但只能两个传其中一个
     *
     * @return List
     */
    @Override
    public Map<String, AuthorityRoleVo> getTargetAndLoginUserRoles(RoleParamsPo roleParamsPo) {
        Map<String, AuthorityRoleVo> perms = new HashMap<>();
        if (StringUtils.isNotEmpty(roleParamsPo.getTargetCode())) {
            AuthorityRoleVo authorityRoleVo = this.getBaseMapper().selectRoleByTargetCode(roleParamsPo.getTargetCode(),roleParamsPo.getTargetType());
            if (authorityRoleVo != null) this.getRoleByTargetCode(authorityRoleVo);
            perms.put("target", authorityRoleVo);
        }
        if (StringUtils.isNotEmpty(roleParamsPo.getRoleCode())) {
            AuthorityRoleVo authorityRoleVo = this.getBaseMapper().selectRoleByRoleCode(roleParamsPo.getRoleCode());
            if (authorityRoleVo != null) this.getRoleByTargetCode(authorityRoleVo);
            perms.put("target", authorityRoleVo);
        }
        perms.put("grante", this.getGranteRoleByLoginUserCode());
        return perms;
    }


    /**
     * 登录用户对象能赋予别人的权限
     * 组织管理员的权限是组织的全部权限
     * 默认角色不参与
     *
     * @param
     * @return AuthorityRoleVo
     */
    public AuthorityRoleVo getGranteRoleByLoginUserCode() {
        AuthorityRoleVo authorityRoleVo = new AuthorityRoleVo();
        UserCacheData user = ThreadUserContext.getCurrentCacheUser();
        //超级管理员
        if (user.getUserCat() == Constants.SUPER_ADMIN) {
            authorityRoleVo.setMenuPermsVo(this.permMenuService.getMenuPermByRoleCode(null,Constants.MENU_ALL));
            authorityRoleVo.setDataPermsVo(this.permDataService.getDataPermCodesNeedConvert(null, true, true));
            this.permDataService.analyseDataPermAsTree(authorityRoleVo.getDataPermsVo());
        }

        //组织管理员,获取组织和组织分类的权限并集
        if (user.getUserCat() == Constants.ORGANIZATION_SUPER_ADMIN||user.getUserCat() == Constants.ORGANIZATION_SYSTEM_ADMIN) {

            List<String> roleCodes = new ArrayList<>();
            List<String> typeCodesList = new ArrayList<>();
            List<String> targetList = this.authorityDataDao.selectOrgTypeCodes(null, user.getOrgCodeJoin());
            targetList.forEach(item -> {
                        typeCodesList.addAll(Arrays.asList(StringUtils.split(item, Constants.DELIMITER)));
                    }
            );
            roleCodes.addAll(this.authorityTargetRoleDao.selectRolesByTargetCodes(typeCodesList, Arrays.asList(Constants.TARGET_ORGANIZATION_TYPE)));
            roleCodes.addAll(this.authorityTargetRoleDao.selectRolesByTargetCodes(Arrays.asList(StringUtils.split(user.getOrgCodeJoin(), Constants.DELIMITER)), Arrays.asList(Constants.TARGET_ORGANIZATION)));
            //获取权限
            authorityRoleVo.setMenuPermsVo(this.permMenuService.getMenuPermByRoleCode(roleCodes,Constants.MENU_ALL));
            authorityRoleVo.setDataPermsVo(this.permDataService.getDataPermCodesNeedConvert(roleCodes, true, true));
            this.permDataService.analyseDataPermAsTree(authorityRoleVo.getDataPermsVo());

        }

        //管理员或其他人赋权，只能赋予自己拥有的
        if (user.getUserCat() == Constants.SYSTEM_ADMIN || user.getUserCat() == Constants.ORDINARY_USER) {
            List<Integer> type=new ArrayList<>();
            type.add(Constants.TARGET_USER);
            type.add(Constants.SYSTEM_ADMIN);
            List<String> roleCodes = this.authorityTargetRoleDao.selectRolesByTargetCodes(Arrays.asList(user.getUserCode()), type);

            authorityRoleVo.setMenuPermsVo(this.permMenuService.getMenuPermByRoleCode(roleCodes,Constants.MENU_ALL));
            authorityRoleVo.setDataPermsVo(this.permDataService.getDataPermCodesNeedConvert(roleCodes, true, true));
            this.permDataService.analyseDataPermAsTree(authorityRoleVo.getDataPermsVo());

        }


        return authorityRoleVo;
    }

    /**
     * 目标对象权限封装，查询时时使用，不需要解析转换数据权限对象中的所属组织和所属部门
     *
     * @param targetCodes
     * @return AuthorityRoleVo
     */
    public AuthorityRoleVo getPermsByTargetCode(List<String> targetCodes, List<Integer> targetTypes) {
        List<String> roleCodes = this.authorityTargetRoleDao.selectRolesByTargetCodes(targetCodes, targetTypes);
        if (roleCodes == null || roleCodes.size() == 0) {
            return null;
        } else {
            AuthorityRoleVo authorityRoleVo = new AuthorityRoleVo();
            authorityRoleVo.setMenuPermsVo(this.permMenuService.getMenuPermByRoleCode(roleCodes,Constants.MENU_ALL));
            authorityRoleVo.setDataPermsVo(this.permDataService.getDataPermCodesNeedConvert(roleCodes, false, true));
            return authorityRoleVo;
        }
    }

    /**
     * 目标对象权限封装，授权时使用，不需要解析转换数据权限对象中的所属组织和所属部门
     *
     * @param authorityRoleVo
     * @return AuthorityRoleVo
     */
    public void getRoleByTargetCode(AuthorityRoleVo authorityRoleVo) {

        authorityRoleVo.setMenuPermsVo(this.permMenuService.getMenuPermListByRoleCode(Arrays.asList(authorityRoleVo.getRoleCode()),Constants.MENU_ALL, false));
        //获取数据权限，并转换为树结构
        authorityRoleVo.setDataPermsVo(this.permDataService.getDataPermCodesNeedConvert(Arrays.asList(authorityRoleVo.getRoleCode()), false, true));

    }


    /**
     * 角色详情查询,用于展示,需要解析
     *
     * @param roleCode
     * @return AuthorityRoleVo
     */
    public AuthorityRoleVo getRoleByRoleCode(String roleCode) {
        AuthorityRoleVo authorityRoleVo = this.getBaseMapper().selectRoleByRoleCode(roleCode);
        //根据菜单code获取对应的菜单实体对象
        authorityRoleVo.setMenuPermsVo(this.permMenuService.getMenuPermByRoleCode(Arrays.asList(roleCode),Constants.MENU_ALL));
        //获取数据权限，并转换为树结构
        authorityRoleVo.setDataPermsVo(this.permDataService.getDataPermCodesNeedConvert(Arrays.asList(roleCode), false, true));
        this.permDataService.analyseDataPermAsTree(authorityRoleVo.getDataPermsVo());

        return authorityRoleVo;
    }

}
